package com.bigcat.gulimall.demo.logs;

import com.bigcat.gulimall.demo.logs.service.AliyunLogServiceImpl;
import com.bigcat.gulimall.demo.mongo.entity.RoadNail;
import com.bigcat.gulimall.demo.mongo.service.RoadNailRepository;
import com.bigcat.gulimall.demo.pojo.PileInfo;
import com.bigcat.gulimall.demo.utils.ByteUtils;
import com.bigcat.gulimall.demo.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.StampedLock;

/**
 * @author sufer_yuan
 * @since 2022/9/1
 */
@RestController
@Slf4j
public class LogController {
    @Autowired
    private AliyunLogServiceImpl aliyunLogService;

    @Autowired
    private RoadNailRepository roadNailRepository;

    private static final ExecutorService executorService = Executors.newFixedThreadPool(12);

    private final ReentrantLock lock = new ReentrantLock();


    /**
     * 筛查无效地桩并且导出到本地
     *
     * @param cityCode  城市id
     * @param beginTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    @GetMapping(value = "/api/searchInvPileAndExport")
    public String searchInvPileAndExport(
            String cityCode,
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime beginTime,
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
        try {
            boolean b = lock.tryLock();
            log.info("获得资源,result:{}", b);
            if (!b) {
                return "正在筛查无效地桩,请耐心等待资源释放";
            }
            if (StringUtils.isEmpty(cityCode) || beginTime == null || endTime == null) {
                return "参数异常";
            }
            new StampedLock();
            boolean before = beginTime.plusDays(20).isBefore(endTime);
            if (before) {
                log.info("筛查时间跨度不能超过20天");
                return "筛查时间跨度不能超过20天";
            }

            List<RoadNail> roadNailList = roadNailRepository.findByCityCode(cityCode);

            if (CollectionUtils.isEmpty(roadNailList)) {
                return "未查询到数据";
            }
            AtomicInteger i = new AtomicInteger(0);
            AtomicInteger y = new AtomicInteger(0);
            ArrayList<PileInfo> pileInfos = new ArrayList<>();
            ArrayList<Future<Integer>> futures = new ArrayList<>();
            for (RoadNail roadNail : roadNailList) {
                if (StringUtils.isEmpty(roadNail.getNailMac()) || StringUtils.isEmpty(roadNail.getStationId())) {
                    continue;
                }

                String mac = ByteUtils.hexMacToByteString(roadNail.getNailMac());
                if (StringUtils.isEmpty(mac)) {
                    return "mac为空";
                }
                String replaceMac = mac.replace("\\", "\\\\");
                if (replaceMac.contains("'")) {
                    replaceMac = replaceMac.replace("'", "\\'");
                }

                if (replaceMac.contains("?")) {
                    replaceMac = replaceMac.replace("?", "\\?");
                }

                if (replaceMac.contains("\"")) {
                    replaceMac = replaceMac.replace("\"", "\\\"");
                }
                String finalReplaceMac = replaceMac;

                //Future 是一个接口，无法直接创建对象，需配合线程池使用.submit()方法返回值Future来保存执行结果；而使用.execute()方法传入Runnable接口无返回值
                //FutureTask 是一个类，可以直接创建对象，其实现了RunnableFuture接口（继承Future接口）
                Future<Integer> future = executorService.submit(() -> {
                    //阿里云日志筛查地桩数据
                    List<Map<String, String>> mapList = aliyunLogService.queryMacInfoByMac(beginTime, endTime, finalReplaceMac);
                    log.info("筛查结果：{},finalMac:{}", mapList, finalReplaceMac);
                    int i1 = i.incrementAndGet();
                    if (CollectionUtils.isEmpty(mapList) || StringUtils.isEmpty(mapList.get(0).get("mac"))) {
                        int yy = y.incrementAndGet();
                        log.info(i1 + "-" + yy + ": deviceId：" + roadNail.getDeviceId() + ",mac:" + roadNail.getNailMac() + ",originalMac:" + mac + ",stationId:" + roadNail.getStationId());
                        PileInfo pileInfo = new PileInfo();
                        pileInfo.setDeviceId(roadNail.getDeviceId());
                        pileInfo.setMac(roadNail.getNailMac());
                        pileInfo.setStationId(roadNail.getStationId());
                        pileInfos.add(pileInfo);
                    }
                    return i1;
                });
                futures.add(future);
            }

            futures.forEach(future -> {
                try {
                    log.info("第{}条数据已筛查分析完毕", future.get(1, TimeUnit.MINUTES));
                } catch (InterruptedException | ExecutionException | TimeoutException e) {
                    e.printStackTrace();
                    lock.unlock();
                }
            });
            ExcelUtils.exportExcel(pileInfos, "海宁" + beginTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "--" + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "未被扫描到的地桩", "D://excel/", "PileInfo", PileInfo.class, "pileInfo.xlsx");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return "ok";
    }


    //            //FutureTask + Callable 方式
//            executorService.submit(new FutureTask<>(() -> {
//                //阿里云日志筛查地桩数据
//                List<Map<String, String>> mapList = aliyunLogService.queryMacInfoByMac(beginTime, endTime, finalReplaceMac);
//                int i1 = i.incrementAndGet();
//                if (CollectionUtils.isEmpty(mapList) || StringUtils.isEmpty(mapList.get(0).get("mac"))) {
//                    int yy = y.incrementAndGet();
//                    log.info(i1 + "-" + yy + ": deviceId：" + roadNail.getDeviceId() + ",mac:" + roadNail.getNailMac() + ",originalMac:" + mac + ",stationId:" + roadNail.getStationId());
//                    PileInfo pileInfo = new PileInfo();
//                    pileInfo.setDeviceId(roadNail.getDeviceId());
//                    pileInfo.setMac(roadNail.getNailMac());
//                    pileInfo.setStationId(roadNail.getStationId());
//                    pileInfos.add(pileInfo);
//                }
//                return i1;
//            }));
}
